<template>
    <div class="editor-operate">
        <!-- 背景区 -->
        <!-- <div class="editor-operate-background" @mousedown="onSelect($event)"></div> -->
        <div class="editor-operate-background" @mousedown="onMousedown($event, 'select')"
             @touchstart="onMousedown($event, 'select')"></div>

        <!-- 边框 -->
        <div class="editor-gridline-border" :style="renderStyle" v-if="!activePiece || activePiece.layers.length == 0"
             @click="insertImage()">
            <svg viewBox="0 0 86 86">
                <rect x="40" y="19" width="6" height="48" rx="3"></rect>
                <rect x="19" y="40" width="48" height="6" rx="3"></rect>
            </svg>
        </div>

        <!-- 滑动区 -->
        <div class="editor-operate-drager" :style="operateStyle" v-if="activeLayer" :status="operateLayerStatus">
            <div @mousedown="onMousedown($event, 'move')" @touchstart="onMousedown($event, 'move')"
                 class="operate-move"></div>

            <button @mousedown="onMousedown($event, 'zoom')" @touchstart="onMousedown($event, 'zoom')"
                    :style="operateIconStyle">
                <svg viewBox="0 0 24 24">
                    <g transform="translate(6, 6)" stroke="none">
                        <polygon points="7.713 0.585 11.16 4.032 11.745 0"></polygon>
                        <polygon points="0 11.745 4.032 11.16 0.585 7.713"></polygon>
                        <polygon points="2.4466 10.4458 1.2996 9.2988 9.1556 1.4428 10.3026 2.5898"></polygon>
                    </g>
                </svg>
            </button>
            <button @mousedown="onMousedown($event, 'rotate')" @touchstart="onMousedown($event, 'rotate')"
                    :style="operateIconStyle">
                <svg viewBox="0 0 24 24">
                    <path d="M18,8.264625 L15.5625,5 L13.125,8.264625 L14.74675,8.264625 C14.7150625,11.8371875 11.813625,14.7345625 8.25,14.7345625 L8.25,13.10225 L5,15.551125 L8.25,18 L8.25,16.366875 C12.7098125,16.366875 16.33925,12.7374375 16.37175,8.264625 L18,8.264625 Z"
                          stroke="none"></path>
                </svg>
            </button>
            <button @click="removeLayer(activeLayer)" :style="operateIconStyle">
                <svg viewBox="0 0 24 24">
                    <rect x="8.5" y="4.5" width="7" height="1" rx="0.5"></rect>
                    <rect x="5.5" y="7.5" width="13" height="1" rx="0.5"></rect>
                    <rect fill="none" stroke-width="2" x="8" y="8" width="8" height="11" rx="2"></rect>
                    <rect x="11" y="12" width="2" height="3" rx="2"></rect>
                </svg>
            </button>
        </div>
    </div>
</template>

<script>
import DesignUtils from '@/utils/DesignUtils.js';
export default {
    props: {
        zoom: { type: Boolean, default: false },
        pieces: { type: Array, default: () => [] },
        activeSurface: { type: Object, default: null },
        activePiece: { type: Object, default: null },
        activeLayer: { type: Object, default: null },
        lock: { type: Array, default: () => [] },// 锁定的图层不可选中, 规则：canvas_name + layer.id
    },
    computed: {
        // 当前显示区
        activeMapper () {
            if (this.activeSurface && this.activePiece) {
                const piece = this.activePiece;
                const surface = this.activeSurface;
                const mapperIndex = surface.mapping.findIndex(mapper => mapper.canvas_name == piece.canvas_name);
                const mapperActive = surface.mapping[mapperIndex];
                return mapperActive;
            } else {
                return null;
            }
        },

        // 渲染器
        renderStyle () {
            if (!this.activePiece || !this.activeSurface) {
                return { display: 'none' }
            } else {
                const piece = this.activePiece;
                const surface = this.activeSurface;
                const mapperIndex = surface.mapping.findIndex(mapper => mapper.canvas_name == piece.canvas_name);
                const mapperActive = surface.mapping[mapperIndex];

                return {
                    width: 100 * mapperActive.width / surface.outer_width + '%',
                    height: 100 * mapperActive.height / surface.outer_height + '%',
                    left: 100 * mapperActive.x / surface.outer_width + '%',
                    top: 100 * mapperActive.y / surface.outer_height + '%',
                    transform: `rotate(${mapperActive.rotate}deg)`,
                }
            }
        },

        // 操作区
        operateStyle () {

            if (this.activeSurface && this.activePiece && this.activeLayer) {

                // 要计算二次旋转角度
                const layer = this.activeLayer;
                const piece = this.activePiece;
                const surface = this.activeSurface;
                const index = surface.mapping.findIndex(mapper => mapper.canvas_name == piece.canvas_name);
                const mapper = surface.mapping[index];

                // 获取元素中间真实位置
                const x1 = mapper.x + layer.x + 0.5 * layer.w;
                const y1 = mapper.y + layer.y + 0.5 * layer.h;
                const x2 = mapper.x + 0.5 * mapper.width;
                const y2 = mapper.y + 0.5 * mapper.height;

                const point = DesignUtils.pointRotate(x1, y1, -mapper.rotate, x2, y2)

                const width = layer.w / surface.outer_width;
                const height = layer.h / surface.outer_height;
                const left = (point.x - 0.5 * layer.w) / surface.outer_width;
                const top = (point.y - 0.5 * layer.h) / surface.outer_width;
                const rotate = mapper.rotate + layer.rotate;

                return {
                    width: 100 * width + '%',
                    height: 100 * height + '%',
                    left: 100 * left + '%',
                    top: 100 * top + '%',
                    transform: `rotate(${rotate}deg)`,
                }

            } else {
                return { display: 'non' }
            }
        },

        // 图标旋转角度
        operateIconStyle () {
            let layer_rotate = this.activeLayer.rotate;
            let mapper_rotate = this.activeMapper.rotate;
            return { transform: `rotate(${-layer_rotate - mapper_rotate}deg)` }
        },

        // 图片dpi提示
        operateLayerStatus () {

            if (!this.activePiece) {
                // 没有选中设计面
                return 'high';
            } else if (!this.activeLayer) {
                // 没有选中图层
                return 'high';
            } else if (this.activeLayer.type == 'image') {

                const now_dpi = 300; // 当前dpi
                const piece = this.activePiece;
                const layer = this.activeLayer;

                const scale = Math.max(piece.real_width / piece.canvas_width, piece.real_height / piece.canvas_height);
                const realW = layer.w * scale;
                const realH = layer.h * scale;
                const imageDpi = Math.min(layer.cutW / realW, layer.cutW / realW) * now_dpi;

                if (imageDpi >= 150) {
                    return 'high';
                } else if (imageDpi < 150 && imageDpi >= 75) {
                    return 'middle';
                } else if (imageDpi < 75) {
                    return 'low';
                }
            } else {
                return 'high';
            }
        }
    },

    methods: {

        // 获取缩放大小
        getScale () {
            if (this.$el && this.activeSurface) {
                let warper = this.$el.getBoundingClientRect();
                let surface = this.activeSurface;
                let offset = 0; // 和边框的间距
                let warperWidth = warper.width - offset * 2;
                let warperHeight = warper.height - offset * 2;
                let surfaceWidth = surface.outer_width;
                let surfaceHeight = surface.outer_height;

                return Math.min(warperWidth / surfaceWidth, warperHeight / surfaceHeight) || 1;
            } else {
                return 1;
            }
        },

        // 图片裁剪样式
        getImageCropStyle (item) {

            // cutX,cutY,cutW,cutH 表示相对图片裁剪的的像素
            // 图片裁剪cutX、cutY必定为正数
            // 业务逻辑为，把图片按cut裁剪后，拉伸放到容器中

            let w = item.image_w * item.w / item.cutW;
            let h = item.image_h * item.h / item.cutH;
            let x = -item.cutX * item.w / item.cutW;
            let y = -item.cutY * item.h / item.cutH;

            return {
                width: 100 * w / item.w + '%',
                height: 100 * h / item.h + '%',
                left: 100 * x / item.w + '%',
                top: 100 * y / item.h + '%',
            }
        },

        removeLayer (layer) {
            this.$emit('dispatch:updateLayer', { type: 'remove', layer: layer });
        },

        // 鼠标按下选中时
        onSelect (event, type) {

            const outer = this.$el.getBoundingClientRect();
            const surface = this.activeSurface || {};
            const piecesObject = Object.fromEntries(this.pieces.map((i) => [i.canvas_name, i]));
            const mapping = surface.mapping || [];

            const touch = (event.targetTouches || [])[0];
            const clientX = touch ? touch.clientX : event.clientX;
            const clientY = touch ? touch.clientY : event.clientY;

            const percentX = (clientX - outer.left) / outer.width;  // 点击位置相对容器距离百分比
            const percentY = (clientY - outer.top) / outer.height;

            // 鼠标点击位置，相对于容器
            const x1 = percentX * surface.outer_width;
            const y1 = percentY * surface.outer_height;

            // 点击在里面的元素
            const inside = [];

            // 循环
            mapping.map(mapper => {

                const piece = piecesObject[mapper.canvas_name];

                // 设计区中点的位置
                const pcx = mapper.x + 0.5 * mapper.width;
                const pcy = mapper.y + 0.5 * mapper.height;

                // 鼠标坐标相对于设计区中点经过旋转后的位置，相对于设计区坐标
                const θ1 = (360 - mapper.rotate) * Math.PI / 180;
                const x2 = (x1 - pcx) * Math.cos(θ1) - (y1 - pcy) * Math.sin(θ1) + pcx - mapper.x;
                const y2 = (x1 - pcx) * Math.sin(θ1) + (y1 - pcy) * Math.cos(θ1) + pcy - mapper.y;

                const inpieceX = x2 >= 0 && x2 <= mapper.width;
                const inpieceY = y2 >= 0 && y2 <= mapper.height;

                // 在设计区中，再计算是否在每个图层里面
                inpieceX && inpieceY && piece.layers.map(layer => {

                    // 图层中点的位置
                    const lcx = layer.x + 0.5 * layer.w;
                    const lcy = layer.y + 0.5 * layer.h;

                    const θ2 = (360 - layer.rotate) * Math.PI / 180;
                    const x3 = (x2 - lcx) * Math.cos(θ2) - (y2 - lcy) * Math.sin(θ2) + lcx;
                    const y3 = (x2 - lcx) * Math.sin(θ2) + (y2 - lcy) * Math.cos(θ2) + lcy;

                    const inlayerX = 2 * Math.abs(x3 - lcx) <= layer.w;
                    const inlayerY = 2 * Math.abs(y3 - lcy) <= layer.h;
                    const layerId = piece.canvas_name + layer.id;
                    const isLock = this.lock.indexOf(layerId) >= 0;

                    inlayerX && inlayerY && !isLock && inside.push({ layer: layer, piece: piece });
                });
            });

            // 锁定图层不可选中

            // 选中
            if (inside.length > 0) {
                // 其他设计区内的，默认是最后一条
                let other = inside[inside.length - 1];
                // 当前设计区内的
                let current = other && other.piece == this.activePiece ? other : null;

                if (current) {
                    return current.layer;
                } else if (this.zoom) {
                    // 缩放状态下，只能选中当前片区的图层
                    return other.layer;
                } else if (other) {
                    return other.layer;
                }
            } else {
                return null;
            }
        },

        // 鼠标按下
        onMousedown (event, action) {

            event.preventDefault();
            event.stopPropagation();

            let layer = this.activeLayer;
            let surface = this.activeSurface;
            let piece = this.activePiece;
            let mapper = this.activeMapper;

            const touch = (event.targetTouches || [])[0];
            const clientX = touch ? touch.clientX : event.clientX;
            const clientY = touch ? touch.clientY : event.clientY;

            if (action == 'move' || action == 'select') {

                let selectLayer = this.onSelect(event);

                if (action == 'select') {
                    action = 'move';
                    layer = selectLayer;
                } else {
                    layer = selectLayer || layer;
                }

                if (this.activeLayer != layer) {
                    this.$emit('dispatch:updateLayer', { type: 'active', layer: layer });

                    if (layer) {
                        piece = this.pieces.filter(i => i.layers.indexOf(layer) >= 0)[0];
                        mapper = surface.mapping.filter(i => i.canvas_name == piece.canvas_name)[0];
                    }

                }
            }


            if (layer && /move|zoom|rotate|remove/.test(action)) {

                let mouse = {};
                let scale = this.getScale();

                let outer = this.$el.getBoundingClientRect();
                let left = outer.width * (layer.x + mapper.x) / surface.outer_width;
                let top = outer.height * (layer.y + mapper.y) / surface.outer_height;
                let width = outer.width * layer.w / surface.outer_width;
                let height = outer.height * layer.h / surface.outer_height;


                mouse.scale = scale;
                mouse.action = action;
                mouse.cache = JSON.parse(JSON.stringify(layer));
                mouse.piece = piece;
                mouse.mapper = mapper;
                mouse.layer = layer;
                mouse.start = new Date().getTime();
                mouse.clientX = clientX;
                mouse.clientY = clientY;
                mouse.centerX = outer.left + left + 0.5 * width;
                mouse.centerY = outer.top + top + 0.5 * height;

                // 一半的对角线长度
                // mouse.diagonal = Math.sqrt(Math.pow(mouse.cache.w, 2)+Math.pow(mouse.cache.h, 2)) / 2;

                this.mouse = mouse;
            }
        },

        // 鼠标移动
        // 要做节流处理，防止频繁操作
        onMousemove (event) {

            if (!this.mouse) { return; }

            event.preventDefault();
            event.stopPropagation();

            const mouse = this.mouse;
            const scale = this.mouse.scale;
            const layer = this.mouse.layer;
            const piece = this.mouse.piece;
            const mapper = this.mouse.mapper;

            const touch = (event.targetTouches || [])[0];
            const clientX = touch ? touch.clientX : event.clientX;
            const clientY = touch ? touch.clientY : event.clientY;
            const offsetX = clientX - mouse.clientX;
            const offsetY = clientY - mouse.clientY;

            if (mouse.action == 'move') {

                const θ = (360 - mapper.rotate) * Math.PI / 180;
                const toX = offsetX * Math.cos(θ) - offsetY * Math.sin(θ);
                const toY = offsetX * Math.sin(θ) + offsetY * Math.cos(θ);

                // 移动
                const x = Math.round(mouse.cache.x + toX / scale);
                const y = Math.round(mouse.cache.y + toY / scale);

                // const size = DesignUtils.rectRealSize(layer.w, layer.h, mouse.cache.rotate)
                // const minX = - 0.5 * layer.w - 0.5 * size.width;
                // const maxX = piece.canvas_width + 0.5 * size.width - 0.5 * layer.w;
                // const minY = - 0.5 * mouse.cache.h - 0.5 * size.height;
                // const maxY = piece.canvas_height + 0.5 * size.height - 0.5 * layer.h;

                // 范围
                const rect1 = {
                    x: 10 / mouse.scale,
                    y: 10 / mouse.scale,
                    w: mapper.width - 20 / mouse.scale,
                    h: mapper.height - 20 / mouse.scale,
                    r: 0,
                }
                const rect2 = {
                    x: x,
                    y: y,
                    w: layer.w,
                    h: layer.h,
                    r: layer.rotate,
                }

                const edge = DesignUtils.rectIsIntersect(rect1, rect2);
                const change = {
                    x: edge.x,
                    y: edge.y,
                };
                this.$emit('dispatch:updateLayer', { type: 'update', layer: layer, change: change });

            } else if (mouse.action == 'zoom') {
                // 缩放
                // 基于中心放大
                // 右上角顶点角度

                // 鼠标拖移弧度
                const angle1 = Math.atan2(offsetY, offsetX);
                // 右上角的角度
                const angle2 = Math.atan2(-mouse.cache.h, mouse.cache.w);
                // 右上角真实角度
                const angle3 = angle2 + (mouse.cache.rotate + mapper.rotate) * Math.PI / 180;
                // 右上角位移变量
                const length = Math.sqrt(Math.pow(offsetY, 2) + Math.pow(offsetX, 2)) * Math.cos(angle3 - angle1);
                // 对角线长度
                const diagonal = Math.sqrt(Math.pow(mouse.cache.w, 2) + Math.pow(mouse.cache.h, 2)) / 2;
                // 最小比例
                const minsize = Math.max(1 / mouse.cache.w, 1 / mouse.cache.h);
                // 长度变化
                const percent = Math.max(minsize, 1 + length / scale / diagonal);
                const change = {}

                change.w = mouse.cache.w * percent;
                change.h = mouse.cache.h * percent;
                change.x = mouse.cache.x + (mouse.cache.w - change.w) / 2;
                change.y = mouse.cache.y + (mouse.cache.h - change.h) / 2;

                // 文字，改字号
                if (layer.type == 'text') {
                    change.font_size = mouse.cache.font_size * percent;
                }

                this.$emit('dispatch:updateLayer', { type: 'update', layer: layer, change: change });


            } else if (mouse.action == 'rotate') {
                // 旋转
                // 右下顶点与中点的向量夹角
                // 鼠标点击时和中心点的角度
                const rotate1 = Math.atan2(mouse.clientY - mouse.centerY, mouse.clientX - mouse.centerX) * 180 / Math.PI;

                // 鼠标旋转后，和中心点的角度
                const rotate2 = Math.atan2(clientY - mouse.centerY, clientX - mouse.centerX) * 180 / Math.PI;

                // 旋转角度=鼠标角度偏差+原来的角度
                const rotate = mouse.cache.rotate + rotate2 - rotate1;

                // 范围是-180至180
                const change = {
                    rotate: Math.round(rotate + 360) % 360
                }
                this.$emit('dispatch:updateLayer', { type: 'update', layer: layer, change: change });

            }
        },

        // 鼠标弹起
        onMouseup (event) {
            if (this.mouse) {
                event.preventDefault();
                event.stopPropagation();
                // 如果太短
                this.mouse = null;
            }
        },

        // 键盘弹起
        onKeyup (event) {

            if (!this.activeLayer) {
                // 没有选中，不管
            } else if (!(!document.activeElement || document.activeElement == document.body || document.activeElement.tagName == 'BUTTON')) {
                // 其他位置输入框
            } else {

                const scale = this.getScale();
                const layer = this.activeLayer;
                const offset = 10 / scale;

                if (event.keyCode == 8) {
                    // 删除
                    if (this.activeSurface.name == "Neck Label Inner") {
                        // 领标不给删
                    } else {
                        this.removeLayer(this.activeLayer)
                    }

                } else if (event.keyCode == 38) {
                    // 上移
                    this.$emit('dispatch:updateLayer', { type: 'update', layer: layer, change: { y: Math.round(layer.y - offset) } });
                } else if (event.keyCode == 40) {
                    // 下移
                    this.$emit('dispatch:updateLayer', { type: 'update', layer: layer, change: { y: Math.round(layer.y + offset) } });
                } else if (event.keyCode == 37) {
                    // 左移
                    this.$emit('dispatch:updateLayer', { type: 'update', layer: layer, change: { x: Math.round(layer.x - offset) } });
                } else if (event.keyCode == 39) {
                    // 右移
                    this.$emit('dispatch:updateLayer', { type: 'update', layer: layer, change: { x: Math.round(layer.x + offset) } });
                }
            }
        },
        insertImage () {
            // 为空的
            this.$emit('dispatch:insertLayer', 'image')
        }
    },

    // 创建
    mounted () {
        window.addEventListener('mousemove', this.onMousemove, false); // 鼠标移动
        window.addEventListener('mouseup', this.onMouseup, false); // 鼠标弹起
        window.addEventListener('touchmove', this.onMousemove, { passive: false }); // 鼠标移动
        window.addEventListener('touchend', this.onMouseup, { passive: false }); // 鼠标弹起
        window.addEventListener('keyup', this.onKeyup, false); // 键盘弹起
    },
    // 销毁
    beforeDestroy: function () {
        window.removeEventListener('mousemove', this.onMousemove); // 鼠标移动
        window.removeEventListener('mouseup', this.onMouseup); // 鼠标弹起
        window.removeEventListener('touchmove', this.onMousemove); // 鼠标移动
        window.removeEventListener('touchend', this.onMouseup); // 鼠标弹起
        window.removeEventListener('keyup', this.onKeyup); // 鼠标弹起
    }
};
</script>

<style lang="scss" scoped>
.editor-operate {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    pointer-events: all;
    z-index: 2;
}

.editor-operate-background {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
}

.editor-operate-drager {
    position: absolute;
    box-sizing: border-box;
    border: 1px dashed #23b98f;

    &::before {
        content: '';
        position: absolute;
        left: -2px;
        top: -2px;
        width: 4px;
        height: 4px;
        border-radius: 2px;
        background: #23b98f;
    }

    &::after {
        content: '';
        position: absolute;
        right: -2px;
        top: -2px;
        width: 4px;
        height: 4px;
        border-radius: 2px;
        background: #23b98f;
    }

    .operate-move {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        cursor: move;

        &::before {
            content: '';
            position: absolute;
            left: -2px;
            bottom: -2px;
            width: 4px;
            height: 4px;
            border-radius: 2px;
            background: #23b98f;
        }

        &::after {
            content: '';
            position: absolute;
            right: -2px;
            bottom: -2px;
            width: 4px;
            height: 4px;
            border-radius: 2px;
            background: #23b98f;
        }
    }

    &[status='middle'] {
        border-color: #edb002;

        &::before {
            background: #edb002;
        }

        &::after {
            background: #edb002;
        }

        .operate-move::before {
            background: #edb002;
        }

        .operate-move::after {
            background: #edb002;
        }
    }

    &[status='low'] {
        border-color: #f44336;

        &::before {
            background: #f44336;
        }

        &::after {
            background: #f44336;
        }

        .operate-move::before {
            background: #f44336;
        }

        .operate-move::after {
            background: #f44336;
        }
    }

    button {
        position: absolute;
        width: 26px;
        height: 26px;
        line-height: 26px;
        border-radius: 26px;
        left: -24px;
        top: -24px;
        background: #23b98f;
        color: #fff;
        border: none;
        margin: 0;
        padding: 0;
        text-align: center;
        font-size: 18px;

        svg {
            width: 24px;
            height: 24px;
            color: #fff;
            fill: #fff;
            stroke: #fff;
        }

        &:hover {
            background: #1b9d79;
        }

        &:nth-child(2) {
            left: auto;
            right: -24px;
        }

        &:nth-child(3) {
            left: auto;
            top: auto;
            bottom: -24px;
            right: -24px;
        }

        &:nth-child(4) {
            background: #f0f0f0;

            svg {
                fill: #979797;
                stroke: #979797;
            }

            &:hover {
                background: #f0f0f0;

                svg {
                    fill: #f44336;
                    stroke: #f44336;
                }
            }
        }
    }
}

.editor-gridline-border {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    box-sizing: border-box;
    z-index: 2;
    cursor: pointer;

    &::before {
        content: '';
        position: absolute;
        left: 1px;
        top: 1px;
        right: 1px;
        bottom: 1px;
        background: rgba(220, 246, 254, 0.9);
    }

    svg {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        max-width: 100%;
        max-height: 100%;
        width: 86px;
        height: 86px;
        fill: #5dd3fb;
        transition: all 0.1s;
    }

    &:hover svg {
        width: 110px;
        height: 110px;
    }
}
</style>
